// eee.Sheffield.PZ.Imaging
//
// Copyright ? Ping Zou, 2007
// sg71.cherub@gmail.com



using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using eee.Sheffield.PZ.Math;

namespace eee.Sheffield.PZ.Imaging.ImageFilter
{
    /// <summary>
    /// Threshold using Simple Image Statistics (SIS)
    /// </summary>
    public class SISThreshold : ImageFilter//, IGraylevelImageFilter
    {
        #region Fields
        //private string _flag = "[Image -> Threshold -> SISThreshold]";
        private byte _threshold;
        #endregion

        #region Properties
        //public string Flag() { return _flag; }
        // Threshold property
        public byte Threshold { get { return _threshold; } }
        //public string Log() { return _log; } 
        #endregion

        #region Constructor
        public SISThreshold()
        {
            _flag = "[Image -> Threshold -> SISThreshold]";
        }
        #endregion

        #region Apply filter  
        protected override PZMath_matrix ApplyDoubleGraylevelImageFilter(PZMath_matrix srcMatrix, out string logText)
        {            
            string thresholdLog = "";
            DoThreshold(srcMatrix, out logText);
            //if (_threshold == 0)
            //{
            //    this.DoThreshold(srcMatrix, out thresholdLog);
            //}

            // get source
            int width = srcMatrix.ColumnCount;
            int height = srcMatrix.RowCount;

            // create dstMatrix
            PZMath_matrix dstMatrix = new PZMath_matrix(height, width);

            // threshold
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    // ivert each pixel
                    dstMatrix[y, x] = srcMatrix[y, x] <= _threshold ? 0 : 255;
                }
            }

            logText = thresholdLog;
            return dstMatrix;
        } // ApplyDoubleGraylevelImageFilter()

        protected override PZMath_matrix[] ApplyDoubleColourImageFilter(PZMath_matrix[] srcMatrixArray, out string logText)
        {
            // TODO: add this function
            
            throw new Exception("The method or operation is not implemented.");
        } // ApplyDoubleColourImageFilter()

        #endregion

        public byte DoThreshold(PZMath_matrix srcMatrix)
        {
            return DoThreshold(srcMatrix, out _log);        
        } // DoThreshold();

        /// <summary>
		/// return threshold, only apply to R channel (gray-level image)
		/// </summary>
		/// <param name="srcImg"></param>
		/// <returns></returns>
        private byte DoThreshold(PZMath_matrix srcMatrix, out string logText)
		{
            // get source
            int width = srcMatrix.ColumnCount;
            int height = srcMatrix.RowCount;

			int widthM1 = width - 1;
			int heightM1 = height - 1;
			double exR, eyR, weightR, weightTotalR = 0, totalR = 0;

            // for each line
            for (int y = 1; y < heightM1; y++)
            {
                // for each pixel
                for (int x = 1; x < widthM1; x++)
                {
                    // the equations are:
                    // ex = I(x + 1, y) - I(x - 1, y)
                    // ey = I(x, y + 1) - I(x, y - 1)
                    // weight = max(ex, ey)
                    // weightTotal += weight
                    // total += weight * I(x, y)
                    exR = srcMatrix[y, x + 1] - srcMatrix[y, x - 1];
                    eyR = srcMatrix[y + 1, x] - srcMatrix[y - 1, x];
                    weightR = (exR > eyR) ? exR : eyR;
                    weightTotalR += weightR;
                    totalR += weightR * (srcMatrix[y, x]);
                }
            }
			
			// calculate threshold
			_threshold = (weightTotalR == 0) ? (byte) 0 : (byte) (totalR / weightTotalR);
		
            logText = "Threshold: " + _threshold.ToString();
            //Log("threshold: " + _threshold);
			//System.Diagnostics.Debug.WriteLine("threshold: " + _threshold);

			return _threshold;
		} // DoThreshold()


        /// <summary>
        /// binarize the source image taking into accout the threshold
        /// </summary>
        /// <param name="srcMatrix">source matrix</param>
        /// <returns>bool image</returns>
        public bool[,] DoBinarize(PZMath_matrix srcMatrix)
        {
            return DoBinarize(srcMatrix, out _log);
        } // DoBinarize()       
        private bool[,] DoBinarize(PZMath_matrix srcMatrix, out string logText)
        {
            // get source
            int width = srcMatrix.ColumnCount;
            int height = srcMatrix.RowCount;
            bool[,] binaryImg = new bool[width, height];

            string thresholdLog = "";
            if (_threshold == 0)
            {
                this.DoThreshold(srcMatrix, out thresholdLog);
            }
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (srcMatrix[y, x] <= _threshold)
                        binaryImg[x, y] = true;     // true -- 1 -- black
                    else
                        binaryImg[x, y] = false;    // false -- 0 -- white
                }
            }
            
            logText = "Bianrization succeeds. " + thresholdLog;
            return binaryImg;
        } // DoBinarize()

    }
}
